package com.frinder.base.advisor;

import com.frinder.base.utils.SpelUtils;
import com.frinder.base.utils.StringUtils;
import com.google.common.base.Strings;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * @author frinder
 * @date 2018/8/10
 * @Description: aop 处理 traceId 实现类
 */
@Order(1)
@Component
@Aspect
public class MdcAdvisor {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private BeanFactory beanFactory;

    /**
     * 所有web下controller
     */
    @Pointcut("execution(* com.frinder..web..*(..))")
    public void pointCut() {
    }

    @Before("pointCut() && !@annotation(com.frinder.base.advisor.Mdc)")
    public void beforeAction(JoinPoint joinPoint) {
        try {
            MDC.put("traceId", StringUtils.getTraceId());
            logInfo(logger, joinPoint, "=> 1-开始执行");
        } catch (Exception e) {
        }
    }

    @After("pointCut() && !@annotation(com.frinder.base.advisor.Mdc)")
    public void afterAction(JoinPoint joinPoint) {
        try {
            logInfo(logger, joinPoint, "<= 1-结束执行");
            MDC.clear();
        } catch (Exception e) {
        }
    }

    /**
     * aop spel 处理注解 Mdc
     *
     * @param joinPoint
     * @param mdc
     */
    @Before(value = "@annotation(mdc)")
    public void beforeAction(JoinPoint joinPoint, Mdc mdc) {
        try {
            String traceId = SpelUtils.SPEL_UTILS.generateKey(beanFactory, mdc.value(), joinPoint);
            if (Strings.isNullOrEmpty(traceId)) {
                traceId = StringUtils.getTraceId();
            }
            MDC.put("traceId", traceId);
            logInfo(logger, joinPoint, "=> 2-开始执行");
        } catch (Exception e) {
        }
    }

    @After("@annotation(mdc)")
    public void afterAction(JoinPoint joinPoint, Mdc mdc) {
        try {
            logInfo(logger, joinPoint, "<= 2-结束执行");
            MDC.clear();
        } catch (Exception e) {
        }
    }

    private void logInfo(Logger logger, JoinPoint joinPoint, String message) {
        try {
            logger.info("*** {} => 方法 {}.{} => 参数 {} => 返回值类型 {}",
                    message,
                    joinPoint.getSignature().getDeclaringTypeName(),
                    joinPoint.getSignature().getName(),
                    Arrays.toString(joinPoint.getArgs()),
                    ((MethodSignature) joinPoint.getSignature()).getReturnType()
            );
        } catch (Exception e) {
        }
    }
}
